#include "codec.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpServer.h>
#include <boost/bind.hpp>
#include <set>
#include <stdio.h>

using namespace muduo;
using namespace muduo::net;

class ChatServer : boost::noncopyable {
public:
	ChatServer(EventLoop *loop, const InetAddress &listenAddr) 
		: server_(loop, listenAddr, "ChatServer"),
		  codec_(boost::bind(&ChatServer::OnStringMessage, this, _1, _2, _3)) {
		server_.setConnectionCallback(boost::bind(&ChatServer::OnConnection, this, _1));
		server_.setMessageCallback(boost::bind(&LengthHeaderCodec::OnMessage, &codec_, _1, _2, _3));
	}

	void Start() {
		server_.start();
	}

private:
	void OnConnection(const TcpConnectionPtr &conn) {
		LOG_INFO << conn->localAddress().toIpPort() << " -> "
		         << conn->peerAddress().toIpPort() << " is "
		         << (conn->connected() ? "UP" : "DOWN");
		if (conn->connected()) 
			connections_.insert(conn);
		else
			connections_.erase(conn);
	}

	void OnStringMessage(const TcpConnectionPtr&, const string &message, Timestamp) {
		for (ConnectionList::iterator it = connections_.begin(); it != connections_.end(); ++it) {
			codec_.Send(boost::get_pointer(*it), message);
		}
	}

	typedef std::set<TcpConnectionPtr> ConnectionList;

	TcpServer server_;
	LengthHeaderCodec codec_;
	ConnectionList connections_;
};

int
main(int argc, char **argv) {
	LOG_INFO << "pid = " << getpid();
	if (argc > 1) {
		EventLoop loop;
		uint16_t port = static_cast<uint16_t>(atoi(argv[1]));
		InetAddress serverAddr(port);
		ChatServer server(&loop, serverAddr);
		server.Start();
		loop.loop();
	} else {
		printf("Usage: %s port\n", argv[0]);
	}
}
